package top.amot.forceview

import android.content.Context
import android.graphics.Canvas
import top.amot.forceview.drawitem.*
import top.amot.forceview.theme.I_Theme
import top.amot.forceview.layout.I_Layout
import top.amot.forceview.model.*

class ForceDrawer @JvmOverloads constructor(private val context: Context) {

    val targetLinks  = mutableListOf<AbstractLink<AbstractNode,AbstractNode>>()
    val sourceLinks  = mutableListOf<AbstractLink<AbstractNode,AbstractNode>>()
    val selectedNodes = mutableListOf<AbstractNode> ()

     var selectedNode: AbstractNode? = null
         set(value) {
            field = value
            if(value!=null){
                nodeModel?.linkList?.forEach { link->
                    if (link.source == value) {
                        selectedNodes.add(link.target)
                        targetLinks.add(link)
                    } else if (link.target ==  value) {
                        selectedNodes.add(link.source)
                        sourceLinks.add(link)
                    }
                }
            }else{
                targetLinks.clear()
                sourceLinks.clear()
                selectedNodes.clear()
            }
        }



    private lateinit var theme: I_Theme
    private lateinit var layout: I_Layout
    private var nodeModel: AbstractNodeModel? = null
    private val defaultNodeDrawItem by lazy {   DefaultNodeDrawItem(context) }
    private lateinit var defaultDrawLink :DefaultDrawLink
    private lateinit var drawManager:DrawManager

    fun setDrawManager(drawManager: DrawManager){
        this.drawManager = drawManager
        defaultDrawLink = DefaultDrawLink(context,drawManager)
    }

     fun setNodeModel(nodeModel: AbstractNodeModel){
        this.nodeModel = nodeModel
    }

    fun configLayout(layout: I_Layout) {
        this.layout = layout
    }

    fun configTheme(theme: I_Theme) {
        theme.measureText()
        this.theme = theme
    }

    fun init(theme: I_Theme,layout: I_Layout,nodeModel: AbstractNodeModel,drawManager: DrawManager){
        configTheme(theme)
        setNodeModel(nodeModel)
        setDrawManager(drawManager)
        configLayout(layout)
    }


    fun drawLinks(canvas: Canvas, links: List<AbstractLink<AbstractNode,AbstractNode>>) {
        links.forEach {
            drawLink(canvas, it)
        }
    }

    fun drawLink(canvas: Canvas, link: AbstractLink<AbstractNode,AbstractNode>) {
        val isSelectNode = selectedNode != null && selectedNode == link.source || selectedNode == link.target
        getDrawLink(link).draw(canvas, theme, layout, link, isSelectNode)
    }


    fun drawNodes(canvas: Canvas, nodes: List<AbstractNode>) {
        nodes.forEach {
            drawNode(canvas, it)
        }
    }

    fun drawNode(canvas: Canvas, node: AbstractNode) {
        getDrawItem(node).draw(canvas, theme, node, false)
    }

    private fun getDrawLink(link: AbstractLink<AbstractNode,AbstractNode>): AbstractDrawLink< AbstractLink<AbstractNode,AbstractNode>> {
        return drawManager.findDrawLink(link)?:defaultDrawLink
    }

    private fun getDrawItem(node: AbstractNode): AbstractDrawItem<AbstractNode> {
        return drawManager.findDrawItem(node)?:defaultNodeDrawItem
    }

    fun drawForce(canvas: Canvas) {
        drawLinks(canvas, nodeModel!!.linkList)
        drawNodes(canvas, nodeModel!!.nodeList)
        drawLinks(canvas, targetLinks)
        drawLinks(canvas, sourceLinks)
        drawNodes(canvas, selectedNodes)
    }
 
    companion object {
        const val DEFAULT_TEXT_SIZE_SP = 13
        const val LOW = -1
    }
}